/* ==================================================================== *
 *
 * This file is part of Mapics Framework.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @author Andrey Cherkashin <action.open@gmail.com>
 *
 * ==================================================================== */

/**
 * Class to make map layer by Yandex Maps API.
 *
 * @package mapics
 * @static
 * @author Andrey Cherkashin <action.open@gmail.com>
 */
mapics.MapLayerYandex = function()
{
    // Map overlay levels
    this.m_Overlays = {};

    // Map event listeners
    this.m_Listeners = [];
};

/**
 * Inheritance from MapLayer class
 */
mapics.MapLayerYandex.prototype = new mapics.MapLayer();

/** ------------------------------------------------------------------------- **
 *  ACTIONS
 ** ------------------------------------------------------------------------- **/

/**
 * Shows Yandex Map in specific div by loading specific privider JS file using
 * AJAX. After that, calls callback function.
 *
 * @param mapDiv   (HTMLObject) Div for map layer
 * @param complete (Callback) Callback function
 *
 * @return mapics.MapLayerYandex
 */
mapics.MapLayerYandex.prototype.show = function( mapDiv, complete )
{
    var self = this;

    // Save map div
    this.m_MapDiv = mapDiv;

    mapics.requestJS(
        "http://api-maps.yandex.ru/1.1/index.xml?loadByRequire=1&key=AOdJiE0BAAAAF1wMXwMAuUFP_cx2ZuDBJm7Y7oR8ezkB_1EAAAAAAAAAAAADtvWwY2tiwfMg5x3pTLwqmzFUHQ==",
        function()
        {
            YMaps.load(function(){
                self.m_Map = new YMaps.Map(mapDiv);
                self.m_Map.setCenter( new YMaps.GeoPoint(37.632576003670714, 55.75806608183598), 12 );
                self.m_Map.enableScrollZoom({ smooth: true });

                if( complete ) {
                    complete();
                }
            });
        }
    );

    return this;
};

/**
 * Hides Yandex map and destroy layer
 *
 * @return mapics.MapLayerYandex
 */
mapics.MapLayerYandex.prototype.hide = function()
{
    if( this.m_Map ) {
        this.m_Map.removeAllOverlays();
        this.m_Map.destructor();

        delete this.m_Map;
    }
    
    return this;
};

/**
 * Smooth move map to specific coordinates
 *
 * @param center {
 *     'lat': (double) Latitude,
 *     'lng': (double) Longitude
 * }
 *
 * @return mapics.MapLayerYandex
 */
mapics.MapLayerYandex.prototype.panTo = function(center)
{
    this.m_Map.panTo( new YMaps.GeoPoint(center.lng, center.lat) );
    return this;
};

/**
 * Adds event listener on some event with that map layer
 *
 * @param eventName (string) Mapics Event name
 * @param handler   (function) Event Handler
 *
 * @return mapics.MapEventListener
 */
mapics.MapLayerYandex.prototype.addListener = function(eventName, handler)
{
    var event;
    
    switch(eventName)
    {
        case "idle": event = this.m_Map.Events.MoveEnd; break;
        default:     event = eventName;                 break;
    }

    // Create yandex's listener
    var listenerYandex = YMaps.Events.observe(this.m_Map, event, handler);

    // Return our listener
    return ( this.m_Listeners[ this.m_Listeners.length ] = new mapics.MapEventListener(eventName, listenerYandex, handler) );
};

/**
 * Removes event listener from that map layer
 *
 * @param eventListener (mapics.MapEventListener)
 *
 * @return mapics.MapLayer
 */
mapics.MapLayerYandex.prototype.removeListener = function(eventListener)
{
    // Remove yandex's listener
    eventListener.getListener().disable();
    eventListener.getListener().cleanup();

    for(var i = 0, max = this.m_Listeners.length; i < max; i++)
    {
        if( this.m_Listeners[i] == eventListener ) {
            this.m_Listeners.splice(i, 1);
            break;
        }
    }

    eventListener.setListener(null);

    return this;
};

/** ------------------------------------------------------------------------- **
 *  AGGREGATION
 ** ------------------------------------------------------------------------- **/

/**
 * Returns this map layer's overlay by specific level
 *
 * @param level (int) Z-Index for this overlay
 *
 * @return mapics.MapLayerYandexOverlay
 */
mapics.MapLayerYandex.prototype.getOverlay = function(level)
{
    // Check for existed overlay
    if( this.m_Overlays[level] ) {
        return this.m_Overlays[level];
    }

    // Create new overlay
    this.m_Overlays[level] = new mapics.MapLayerYandexOverlay(level);
    this.m_Map.addOverlay( this.m_Overlays[level] );

    return this.m_Overlays[level];
};

/** ------------------------------------------------------------------------- **
 *  PROPERTIES
 ** ------------------------------------------------------------------------- **/

/**
 * Returns current provider name
 *
 * @return string
 */
mapics.MapLayerYandex.prototype.getProviderName = function() {
    return "yandex";
};

/**
 * Returns current type of this map layer
 *
 * @see MapLayer constructor's consts: TYPE_*
 *
 * @return int|null
 */
mapics.MapLayerYandex.prototype.getType = function()
{
    var typeId = this.m_Map.getType();

    if( typeId == YMaps.MapType.MAP ) {
        return mapics.MapLayer.TYPE_MAP;
    } else if( typeId == YMaps.MapType.SATELLITE ) {
        return mapics.MapLayer.TYPE_SATELLITE;
    } else if( typeId == YMaps.MapType.HYBRID ) {
        return mapics.MapLayer.TYPE_HYBRID;
    }

    return null;
};

/**
 * Sets current type of this map layer
 *
 * @see MapLayer constructor's consts: TYPE_*
 *
 * @param type (int) New map layer type
 *
 * @return mapics.MapLayerYandex
 */
mapics.MapLayerYandex.prototype.setType = function(type)
{
    switch( type )
    {
        case mapics.MapLayer.TYPE_MAP:
            this.m_Map.setType(YMaps.MapType.MAP);
            break;
        case mapics.MapLayer.TYPE_SATELLITE:
            this.m_Map.setType(YMaps.MapType.SATELLITE);
            break;
        case mapics.MapLayer.TYPE_HYBRID:
            this.m_Map.setType(YMaps.MapType.HYBRID);
            break;
    }

    return this;
};

/**
 * Returns current center of this map layer
 *
 * @return {
 *     'lat': (double) Latitude,
 *     'lng': (double) Longitude
 * }
 */
mapics.MapLayerYandex.prototype.getCenter = function()
{
    var center = this.m_Map.getCenter();

    return {
        'lat': center.getLat(),
        'lng': center.getLng()
    };
};

/**
 * Sets current center of this map layer
 *
 * @param center {
 *     'lat': (double) Latitude,
 *     'lng': (double) Longitude
 * }
 *
 * @return mapics.MapLayerYandex
 */
mapics.MapLayerYandex.prototype.setCenter = function(center)
{
    this.m_Map.setCenter( new YMaps.GeoPoint(center.lng, center.lat) );
    return this;
};

/**
 * Returns current zoom of this map
 *
 * @return int
 */
mapics.MapLayerYandex.prototype.getZoom = function() {
    return this.m_Map.getZoom();
};

/**
 * Sets current zoom of this map layer
 *
 * @param zoom (int) Zoom
 *
 * @return mapics.MapLayerYandex
 */
mapics.MapLayerYandex.prototype.setZoom = function(zoom)
{
    this.m_Map.setZoom( zoom );
    return this;
};